package org.zhuzx.util;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zhuzx 2022/10/17
 */
public class ObjectDataUtil {

	/**
	 * 此方法适用于直接在代码中生成字典文本的场景，getNameById会被循环执行，所以不要在其中读库或者调用接口。
	 * @param <T> 目标数据对象的类型
	 * @param <I> id值，也就是字典值的类型。
	 * @param <N> name值，也就是字典文本的类型。
	 */
	public static <T,I,N> void setNameById(List<T> dataList,
										   Function<T,I> getId, Function<I,N> getNameById, BiConsumer<T,N> setName) {
		Set<I> ids = dataList.stream().map(getId).filter(Objects::nonNull).collect(Collectors.toSet());
		if (ids.isEmpty()) {//所有对象的id值都为空
			return;
		}
		Map<I,N> idNameMapping = ids.stream().collect(Collectors.toMap(id -> id, getNameById));
		setNameById(dataList, getId, idNameMapping, setName);
	}

	/**
	 * 此方法适用于从map中获取字典文本的场景，同时作为底层方法被其它setNameById方法调用。
	 * @param <T> 目标数据对象的类型
	 * @param <I> id值，也就是字典值的类型。
	 * @param <N> name值，也就是字典文本的类型。
	 */
	public static <T,I,N> void setNameById(List<T> dataList,
										   Function<T, I> getIdFromData, Map<I, N> idNameMapping, BiConsumer<T, N> setName) {
		if (idNameMapping.values().stream().allMatch(Objects::isNull)) {//流为空时allMatch也会返回true
			return;
		}
		dataList.forEach(obj -> {
			I id = getIdFromData.apply(obj);
			if (id != null) {
				setName.accept(obj, idNameMapping.get(id));
			}
		});
	}

	/**
	 * 此方法适用于批量查询字典文本的场景，queryDictListByIds只会被执行一次。
	 * @param <T> 目标数据对象的类型
	 * @param <D> 查询得到的字典对象类型（即完整的字典数据）
	 * @param <I> id值，也就是字典值的类型。
	 * @param <N> name值，也就是字典文本的类型。
	 */
	public static <T,D,I,N> void setNameById(List<T> dataList,
											 Function<T,I> getIdFromData, Function<Collection<I>,List<D>> queryDictListByIds,
											 Function<D,I> getIdFromDict, Function<D,N> getNameFromDict,
											 BiConsumer<T,N> setName) {
		Set<I> ids = dataList.stream().map(getIdFromData).filter(Objects::nonNull).collect(Collectors.toSet());
		if (ids.isEmpty()) {//所有对象的id值都为空
			return;
		}
		Map<I,N> idNameMapping = queryDictListByIds.apply(ids).stream().collect(Collectors.toMap(getIdFromDict, getNameFromDict));
		setNameById(dataList, getIdFromData, idNameMapping, setName);
	}

	/**
	 * 将一个文本值以逗号分隔的形式拼接到一个字段值里面，仅在尾部追加，保留字段的原有值。
	 */
	public static <T> void addValuePartToField(T object, Function<T,String> getValue, String valuePart, BiConsumer<T,String> setValue) {
		String oldValue = getValue.apply(object);
		setValue.accept(object, oldValue == null ? valuePart : oldValue + "," + valuePart);
	}
	
	/** 获取对象中的某个属性值，当对象本身为null时返回null。*/
	public static <T,V> V getValue(T obj, Function<T,V> getValue) {
		return obj == null ? null : getValue.apply(obj);
	}

}